import gobject

from db import db
from fvutil import fvcon
from util import config

import random
import time

class GroupManager(gobject.GObject):
    
    __gsignals__ = {
        'return_groups' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                (gobject.TYPE_PYOBJECT,)),
        'group_appeared' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                (gobject.TYPE_PYOBJECT,)),
    }
    
    def __init__(self, async, my_id):
        gobject.GObject.__init__(self)
        _db = db.get_database(config.get('fv', 'db-path'), config.get('fv', 'object-db'))
        self._table = _db.get_or_create(GroupTable)
        self._type = fvcon.GROUP

    # ObjectManager API
    def get(self, oid):
        return self.to_flash(self._table.get(oid))
    
    def get_all(self):
        return map(self.to_flash, self._table.get_all())    
        
        
    def on_new_group(self, obj, data):
        name = 'New group'
        gid = random.randint(1,1000000)
        self._table.add_group(gid, name)
        obj.updateObject(self, {'subcommand': fvcon.ADD,
                                'type': fvcon.GROUP,
                                'id':gid,
                                'label':name,
                                'status':fvcon.AVAILABLE
                                })
    
    def on_add_user_to_group(self, obj, gid, uid):
        self._table.add_user_to_group(gid, uid) 
    
    def on_del_user_from_group(self, obj, gid, uid):
        self._table.del_user_from_group(gid, uid)
    
    def on_show_group(self, obj, data):
        raise NotImplementedError
    
    def on_del_group(self, obj, data):
        raise NotImplementedError
    
    def on_update_group_name(self, obj, gid, name):
        self._table.update_group_name(gid, name)
    
    def to_flash(self, header_dict):
        return {'type':fvcon.GROUP,
                'subcommand': fvcon.ADD,
                'label':header_dict['name'],
                'members':header_dict['members']}
        
        header_dict['type'] = fvcon.GROUP
        return header_dict
  
gobject.type_register(GroupManager)
# Provides the same interface as the ObjectTable  
class GroupTable(db.Table):
    
    def __init__(self):
        db.Table.__init__(self)
        
    def _init(self):
        # This is kind of bad. We are reproducing users here; we have users
        # in the presence service as well. Oh well.
        self._conn.execute('''
            CREATE TABLE users
            (uid INTEGER PRIMARY KEY, name STRING, timestamp INTEGER)''')
        self._conn.execute('''
            CREATE TABLE groups
            (gid INTEGER PRIMARY KEY, name STRING, created INTEGER, deleted INTEGER)''')
        self._conn.execute('''
            CREATE TABLE groupmembers
            (gid INTEGER, uid INTEGER, joined INTEGER, left INTEGER, PRIMARY KEY(gid, uid))''')
           
    def _drop(self):
        self._conn.execute('''
            drop table users
            ''')
        self._conn.execute('''
            drop table groups
            ''')
        self._conn.execute('''
            drop table groupmembers
            ''')    
        
    def get(self, gid):
        c = self._conn
        groups = c.execute(''' SELECT * FROM groups WHERE gid=? ''', (gid,))
        group = None
        if groups:
            group = groups[0]
        if group is None:
            raise ValueError
        rows = c.execute(''' SELECT * FROM groupmembers INNER JOIN users ON groupmembers.uid = users.uid WHERE gid=? ''', (gid,))
        print gid, rows
        result = {'gid':group['gid'], 'name':group['name'], 'created':group['created'], 'deleted':group['deleted'], active:group['deleted'] is not False, 'members':[]}
        for r in rows:
            if r['left'] == -1:
                result['members'].append(r)
        return result
    
    def get_all(self):
        c = self._conn
        rows = c.execute(''' SELECT * FROM groups ''')
        groups = {}
        for group in rows:
            groups[group['gid']] = {'gid':group['gid'], 'name':group['name'], 'created':group['created'], 'deleted':group['deleted'], 'active':group['deleted'] is not False, 'members':[]}
        
        print groups
        for (gid, group) in groups.iteritems():
            rows = c.execute(''' SELECT * FROM groupmembers INNER JOIN users ON groupmembers.uid = users.uid WHERE gid=? ''', (gid,))
            for r in rows:
                if r['left'] == -1:
                    group['members'].append(r)
        print 'RETURNING GROUPS!!_!__!_!_!',groups.values()
        return groups.values()
    
    
    def __get_user_dets(self, uid):
        c = self._conn
        [user] = c.execute(''' SELECT * FROM users WHERE uid=?''', (uid,))
        return user
    
    def __get_group_dets(self, gid):
        c = self._conn
        [group] = c.execute(''' SELECT * FROM groups WHERE gid=?''', (gid,))
        return group
    
    def add_group(self, gid, name):
        c = self._conn
        print gid,name,int(time.time()), None
        c.execute(''' INSERT INTO groups VALUES (?,?,?,?) ''', (gid, name, int(time.time()), None))
        
    def add_user_to_group(self, uid, gid):
        try:
            # Migh be added multiple times, can't let that happen
            c = self._conn
            c.execute(''' INSERT INTO groupmembers VALUES (?,?,?,?) ''', (gid, uid, int(time.time()), None))
        except:
            c = self._conn
            c.execute(''' UPDATE groupmembers SET left=? WHERE uid=? AND gid=? ''', (-1, uid,gid))
        
    def del_user_from_group(self, uid, gid):
        c = self._conn
        c.execute(''' UPDATE groupmembers SET left=? WHERE uid=? AND gid=? ''', (int(time.time()), uid, gid))
    
    def update_group_name(self, gid, name):
        c = self._conn
        c.execute(''' UPDATE groups SET name=? WHERE gid=? ''', (name, gid))
    
    def __db_to_py(self, row):
        row['meta'] = pickle.loads(row['meta'].encode('ascii'))
        row['dests'] = pickle.loads(row['dests'].encode('ascii'))
        return row
    
    def __py_to_db(self, data):
        data['meta'] = pickle.dumps(data['meta'])
        data['dests'] = pickle.dumps(data['dests'])
        return data
    